
// ---------------------------------------------------
// L1 - data cache module
// ---------------------------------------------------
// SRAM capacity  : 4MB = 16Kx64x4 (sets,line size,associativity)
// Num Sets       : 16K
// Line size      : 64 bytes
// Associativity  : 4 way
//
// ---------------------------------------------------
// Bit Descriptions
// ---------------------------------------------------
// Address bits   : 32 
// Byte select    : 6
// Index          : 14
// Tag            : 12
// LRU            : 6 
// MESI           : 2
//changed copy
module L1_data_cache(addr, ENbar, DQ_RDY);
input [31:0] addr;
input ENbar;
output DQ_RDY;
reg DQ_RDY;
reg [5:0] curLRUbits;
reg [1:0] curWay;
reg Reset, Access;
wire [5:0] NS;
wire [1:0] LRU;

LRU lru_dev(curLRUbits,curWay,Reset,Access,NS,LRU);
//parameter nSets       = 16384;
//parameter nBytesInLine= 64;
//parameter nWays       = 4;
//parameter nTagBits    = 12;
//parameter nIndexBits  = 14;
//parameter nByteSelBits= 6;
parameter initialLRUBits = 6'b000000; // LRU 0 < 1 < 2 < 3 MRU

// Assume 32 bit data bus width
// 32 bit Data Array arranged as [bytes in line x num sets x ways]
reg [31:0] DataArray [15:0][16383:0][3:0];
// 12 bit Tag Array arranged as [num sets x num ways]
reg [11:0] TagArray [16383:0][3:0];
// 2 bits MESI Array arranged as [num sets x num ways]
reg [1:0] MESIArray [16383:0][3:0];
// 6 bit LRU Array arranged as [num sets]
reg [5:0] LRUArray[16383:0]; 		//shouldn't we only have 6 LRU bits, why do we need 6 LRU bits per set?
// Valid bit array arranged as [num sets x num ways]
reg ValidBitArray [16383:0][3:0];

initial /*Initialize the data structure*/
begin : InitializeDataStructure
    integer I;
    integer J;
    for(I = 0; I < 16384; I = I+1) begin
        for (J=0; J<4; J=J+1) begin
          ValidBitArray[I][J] = 0;
          MESIArray[I][J] = 0;
        end
        LRUArray[I] = initialLRUBits;
    end  
    DQ_RDY = 1'b0;
end

always @ (negedge ENbar)
begin : MainBlock
    integer index, byteSel, way;
    reg read;
    reg [11:0] tag;
    DQ_RDY = 1'b0;
    read = 1'b0;
    index = addr[19:6];
    byteSel  = addr[5:0];
    tag = addr[31:20];

    way = -1;

    // Look in the 4 way
    // cache for the matching tag bits
    case(tag)
		TagArray[index][0]: 
        if (ValidBitArray[index][0])
			way = 0;
		TagArray[index][1]: 
        if (ValidBitArray[index][1])
			way = 1;
		TagArray[index][2]: 
		if (ValidBitArray[index][2])
			way = 2;
		TagArray[index][3]: 
		if (ValidBitArray[index][3])
			way = 3;
       default:
			way = -1;
    endcase
  
                  
    if (way < 0) 
        begin : CacheMiss
        // Make memory request to L2 stub
		// Update MESIArray
//			MESIArray [index][way] = ?	//set to variable from L2 stub, M,E or S state

			// Update ValidBitArray
			ValidBitArray [index][way] = 0;
			
			// perform LRU
			// put the data in the LRU way
			// update LRU bits
			curWay = LRU;
			curLRUbits = LRUArray[index];
			Access = 1'b1;
			#1 LRUArray[index] = NS;
			
			DataArray[byteSel][index][way] = addr;
			TagArray[index][way] = addr[31:20];
			{Access,DQ_RDY} = 2'b01;
        	
        // so on.. 
        end  
    else
        begin : CacheHit
			// perform LRU
			// Update LRU bits
        	curWay = way;
			curLRUbits = LRUArray[index];
			Access = 1'b1;
			#1 LRUArray[index] = NS;
			DataArray[byteSel][index][way] = addr;
            TagArray[index][way] = addr[31:20];
        
		// Return Data		
		
			{Access,DQ_RDY} = 2'b01;
        end
    
    if(read)   // If it was a write operation 
        begin : ReadOperation
        
        end    // end of read (if statement)
    
    else 
        begin : WriteOperation
            way = 2; 
            if (!ValidBitArray[index][way] /* and */) begin
                begin
                curWay = way;
                curLRUbits = LRUArray[index];
                Access = 1'b1;
				
                #1 LRUArray[index] = NS;	// always statements blocks run all at once, begin and end have no affect
                DataArray[byteSel][index][way] = addr;
                TagArray[index][way] = addr[31:20];
                ValidBitArray[index][way] = 0;
			
	// I commented out the next 2 lines because we only want to output at the end of trace
            //    $display("Index = %d\tByte Select = %d\tWay = %d %h\n",index,byteSel,way, LRU);  
             //   $display("Data  = %h\tLRU = %b\n",DataArray[byteSel][index][way],NS); 
                {Access,DQ_RDY} = 2'b01;
                end
            end // end of if statement
        end     // end of write operation

end // end of MainBlock
endmodule